package com.syp.auth.service.base.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.syp.auth.common.Constants;
import com.syp.auth.dao.po.RoleEntity;
import com.syp.auth.dao.po.RoleResourceEntity;
import com.syp.auth.dao.po.UserEntity;
import com.syp.auth.dao.po.UserRoleEntity;
import com.syp.auth.dao.repository.RoleRepository;
import com.syp.auth.dao.repository.RoleResourceRepository;
import com.syp.auth.dao.repository.UserRepository;
import com.syp.auth.dao.repository.UserRoleRepository;
import com.syp.auth.domain.vo.UserVo;
import com.syp.auth.service.base.UserServiceI;
import com.syp.auth.common.MD5Util;

@Service
public class UserServiceImpl implements UserServiceI {

	@Autowired
	private UserRepository userRepository;
	@Autowired
	private UserRoleRepository userRoleRepository;
	@Autowired
	private RoleRepository roleRepository;
	@Autowired
	private RoleResourceRepository roleResourceRepository;

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void add(UserVo user) {
		UserEntity us = new UserEntity();
		BeanUtils.copyProperties(user, us);
		us.setPassword(MD5Util.md5(user.getPassword()));
		Calendar calNow = Calendar.getInstance();
		us.setCreateTime(calNow.getTime());
		us.setLastUpdate(calNow.getTime());
		calNow.set(Calendar.HOUR_OF_DAY, 0);
		calNow.set(Calendar.MINUTE, 0);
		calNow.set(Calendar.SECOND, 0);
		calNow.set(Calendar.MILLISECOND, 0);
		us.setRegisterDate(calNow.getTime());
		this.userRepository.save(us);
	}

	@Override
	public void delete(long id) {
		this.userRepository.delete(id);
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void deleteBatch(List<Long> ids) {
		this.userRoleRepository.deleteByUserIdList(ids);
		this.userRepository.deleteBatch(ids);
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void edit(UserVo user) {
		UserEntity userEntity = this.userRepository.findOne(user.getId());
		userEntity.setEmail(user.getEmail());
		userEntity.setSex(user.getSex());
		userEntity.setTel(user.getTel());
		if (!Constants.isSuperMan(user.getId())) {
			userEntity.setStatus(user.getStatus());
		}
		userEntity.setLastUpdate(Calendar.getInstance().getTime());
		this.userRepository.save(userEntity);
	}

	@Override
	public UserVo get(Long id) {
		UserVo userVo = new UserVo();
		UserEntity userEntity = this.userRepository.findOne(id);
		this.reverseTrans(userEntity, userVo);
		return userVo;
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void grant(UserVo user, List<Long> limitIds) {
		if (limitIds != null && !limitIds.isEmpty()) {
			this.userRoleRepository.deleteByUserIdLimitedInMyDomain(user.getId(), limitIds);
		} else {
			this.userRoleRepository.deleteByUserId(user.getId());
		}

		if (user.getRoleIdsString() != null) {
			List<UserRoleEntity> userRoleList = new LinkedList<>();
			for (String roleId : user.getRoleIdsString().split(",")) {
				UserRoleEntity ur = new UserRoleEntity();
				ur.setRoleId(Long.valueOf(roleId));
				ur.setUserId(user.getId());
				userRoleList.add(ur);
			}
			this.userRoleRepository.save(userRoleList);
		}
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void grantBatch(UserVo user, List<Long> limitIds) {
		for (String userId : user.getIdsString().split(",")) {
			if (limitIds != null && !limitIds.isEmpty()) {
				this.userRoleRepository.deleteByUserIdLimitedInMyDomain(Long.valueOf(userId), limitIds);
			} else {
				this.userRoleRepository.deleteByUserId(Long.valueOf(userId));
			}
			if (user.getRoleIdsString() != null) {
				List<UserRoleEntity> userRoleList = new LinkedList<>();
				for (String roleId : user.getRoleIdsString().split(",")) {
					UserRoleEntity ur = new UserRoleEntity();
					ur.setRoleId(Long.valueOf(roleId));
					ur.setUserId(Long.valueOf(userId));
					userRoleList.add(ur);
				}
				this.userRoleRepository.save(userRoleList);
			}
		}
	}

	@Override
	public Page<UserVo> pagelist(final UserVo user) {
		Specification<UserEntity> spec = new Specification<UserEntity>() {
			@Override
			public Predicate toPredicate(Root<UserEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> pList = new ArrayList<>();

				if (!StringUtils.isEmpty(user.getUserCode()) && !user.getUserCode().trim().equals("")) {
					pList.add(cb.like(root.get("userCode").as(String.class), user.getUserCode().trim() + "%"));
				}
				if (!StringUtils.isEmpty(user.getEmail()) && !user.getEmail().trim().equals("")) {
					pList.add(cb.like(root.get("email").as(String.class), user.getEmail().trim() + "%"));
				}
				if (!StringUtils.isEmpty(user.getUserName()) && !user.getUserName().trim().equals("")) {
					pList.add(cb.like(root.get("userName").as(String.class), "%" + user.getUserName().trim() + "%"));
				}
				if (!StringUtils.isEmpty(user.getStatus()) && !user.getStatus().trim().equals("")) {
					pList.add(cb.equal(root.get("status"), user.getStatus().trim()));
				}
				return cb.and(pList.toArray(new Predicate[pList.size()]));
			}
		};

		String order = user.getOrder() == null ? "desc" : user.getOrder();
		String sortColumn = user.getSort() == null ? "id" : user.getSort();
		Sort sort = new Sort(Sort.Direction.fromString(order), sortColumn);
		Pageable pageable = new PageRequest(user.getPage() - 1, user.getRows(), sort);
		Page<UserEntity> page = this.userRepository.findAll(spec, pageable);
		List<UserVo> list = new ArrayList<UserVo>();
		if (page.hasContent()) {
			for (UserEntity item : page.getContent()) {
				UserVo u = new UserVo();
				this.reverseTrans(item, u);
				list.add(u);
			}
		}

		return new PageImpl<>(list, pageable, page.getTotalElements());
	}

	@Override
	public void editUserInfo(UserVo userVo) {
		if (userVo.getPassword() != null && !userVo.getPassword().trim().equals("")) {
			UserEntity userEntity = this.userRepository.findOne(userVo.getId());
			userEntity.setPassword(MD5Util.md5(userVo.getPassword()));
		}
	}

	public void trans(UserVo userVo, UserEntity userEntity) {
		if (userVo != null) {
			if (StringUtils.isEmpty(userVo.getId())) {
				BeanUtils.copyProperties(userVo, userEntity);
			} else {
				BeanUtils.copyProperties(userVo, userEntity, new String[] { "password", "registerDate" });
			}
		}
	}

	public void reverseTrans(UserEntity userEntity, UserVo userVo) {
		if (userEntity != null) {
			BeanUtils.copyProperties(userEntity, userVo, new String[] { "password" });

			userVo.setRegisterDate(userEntity.getRegisterDate());

			if (!StringUtils.isEmpty(userEntity.getSex()) && userEntity.getSex().equals("1")) {
				userVo.setSexText("男");
			} else if (!StringUtils.isEmpty(userEntity.getSex()) && userEntity.getSex().equals("2")) {
				userVo.setSexText("女");
			}

			if (!StringUtils.isEmpty(userEntity.getStatus()) && userEntity.getStatus().equals("1")) {
				userVo.setStatusText("启用");
			} else if (!StringUtils.isEmpty(userEntity.getStatus()) && userEntity.getStatus().equals("0")) {
				userVo.setStatusText("未启用");
			}

			List<String> roleIds = new ArrayList<String>();
			List<String> roleNames = new ArrayList<String>();
			List<UserRoleEntity> userRoleEntityList = this.userRoleRepository.getByUserId(userEntity.getId());
			if (!CollectionUtils.isEmpty(userRoleEntityList)) {
				for (UserRoleEntity urs : userRoleEntityList) {
					RoleEntity roleEntity = this.roleRepository.findOne(urs.getRoleId());
					roleIds.add(roleEntity.getId().toString());
					roleNames.add(roleEntity.getRoleName());
				}
			}
			userVo.setRoleIds(roleIds.toArray(new String[roleIds.size()]));
			userVo.setRoleNames(roleNames.toArray(new String[roleNames.size()]));
			userVo.setIsSuperMan(Constants.isSuperMan(userEntity.getId()));
		}
	}

	@Override
	public boolean verifyOldPasswardCorrect(Long id, String oldPassword) {
		UserEntity userEntity = this.userRepository.findOne(id);
		return userEntity.getPassword().equals(MD5Util.md5(oldPassword));
	}

	@Override
	public void updatePassward(Long id, String password) {
		UserEntity userEntity = this.userRepository.findOne(id);
		userEntity.setPassword(MD5Util.md5(password));
		this.userRepository.save(userEntity);
	}

	@Override
	public boolean checkUserCodeUnique(String usercode) {
		boolean unique = false;

		UserEntity u = this.userRepository.getByUserCode(usercode);
		if (u == null) {
			unique = true;
		}
		return unique;
	}

	@Override
	public List<Long> myRoleIdList(Long myId) {
		List<Long> list = new LinkedList<>();
		List<UserRoleEntity> urs = this.userRoleRepository.getByUserId(myId);
		if (urs != null) {
			for (UserRoleEntity ur : urs) {
				list.add(ur.getRoleId());
			}
		}
		return list;
	}

	@Override
	public List<Long> myResIdList(Long myId) {
		List<Long> list = new LinkedList<>();
		List<Long> roleIdList = this.myRoleIdList(myId);
		if (roleIdList != null) {
			List<RoleResourceEntity> rrs = this.roleResourceRepository.getByRoleIdList(roleIdList);
			if (rrs != null) {
				for (RoleResourceEntity rr : rrs) {
					list.add(rr.getResId());
				}
			}
		}
		return list;
	}

}
